#include "Frame.h"
#include <sys/socket.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>

static bool interrupt=false;

static void *Q_thread (void *t){
    int *uq_id = (int*)t;
    Message_queue buff;
    struct msghdr mh;
    int sock=socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in serv_addr;
    struct iovec v[1];
    bzero((char *) &buff, sizeof(buff));
    bzero((char *) &mh, sizeof(mh));
    bzero((char *) &v, sizeof(v));
   
     
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(QUIMERA_PORT);
   
     v[0].iov_base = &buff;
     v[0].iov_len = sizeof(buff);
     mh.msg_name = &serv_addr;
     mh.msg_namelen = sizeof(serv_addr);
     mh.msg_iov = v;
     mh.msg_iovlen = 1;
   
    msgrcv(*uq_id,(struct msgbuf *)&buff,sizeof(buff)-sizeof(long),CLRU,0);
    
    bzero((char *) &buff, sizeof(buff));
    buff.id_message=CLR;
    msgsnd(*uq_id, (struct msgbuf *)&buff,
    sizeof(buff.package)+sizeof(buff.cli_addr),IPC_NOWAIT);
    
    interrupt=true;
    sendmsg(sock, &mh, 0);
}

int main()  {
    
    bool to_queue=false;
    int unpacker_queue_id;
    int log_queue_id; 
    Message_queue inbound_mail;
    Message_queue log_msg;
    char buffer[1500];
    Package *message;
    pthread_t init;
    void *id;
    
    struct msghdr mh;
    struct iovec v[1];
    struct sockaddr_in serv_addr, cli_addr;
    int sockfd, n_bytes_r;
    
    unpacker_queue_id=Message_queue_setup(C_UNPACKER_QUEUE_KEY);
    log_queue_id=Message_queue_setup(LOGGER_QUEUE_KEY);
    
    if(unpacker_queue_id==EXIT_FAILURE and log_queue_id!=EXIT_FAILURE){    
        bzero((char *) &log_msg, sizeof(log_msg));
        log_msg.id_message=LOG_QUEUE_ERR_UNPACKER;
        msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
        sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
        free(message);
        close(sockfd);
        return(EXIT_FAILURE);
    }
    else if(log_queue_id==EXIT_FAILURE){
        std::cout<<"Error, el programa ha fallado al crear la cola de mensajes para el (Desempacador),"
                   "verifique si se ha ejecutado con privilegios de root\n";
        free(message);
        close(sockfd);
        return(EXIT_FAILURE);
        
    }
    
    std::cout<<"Antes\n";
    id=(void*)&unpacker_queue_id;
    pthread_create(&init,NULL,&Q_thread,id);
    std::cout<<"Despues\n";
     bzero((char *) &serv_addr, sizeof(serv_addr));
     bzero((char *) &cli_addr, sizeof(cli_addr));
     bzero((char *) &buffer, sizeof(buffer));
     bzero((char *) &mh, sizeof(mh));
     
     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
     v[0].iov_base = &buffer;
     v[0].iov_len = sizeof(buffer);
     
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_port = htons(QUIMERA_PORT);
     bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr));
     mh.msg_name = &cli_addr;
     mh.msg_namelen = sizeof(cli_addr);
     mh.msg_iov = v;
     mh.msg_iovlen = 1;
     
     bzero((char *) &log_msg, sizeof(log_msg));
     log_msg.id_message=LOG_QUEUE_EVNT_UNPACKER;
     msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
     sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
     
 
     while(!interrupt){
         
         std::cout<<"aqui\n";
         n_bytes_r=recvmsg(sockfd, &mh, 0);    
        std::cout<<"no bloqueo\n";
         if (n_bytes_r>0){
            message=(Package*)&buffer;
            std::cout<<"El mensaje es: "<<int(message->header.type_message)<<std::endl;
 
            bzero((char *)&inbound_mail, sizeof(inbound_mail));
            switch(message->header.type_message){
       
                    case INVESTMENT:{ 
                         inbound_mail.id_message=I;          
                         to_queue=true;
                         
                         bzero((char *) &log_msg, sizeof(log_msg));
                         log_msg.id_message=LOG_QUEUE_EVNT_IN_INVESTMENT;
                         log_msg.cli_addr=cli_addr;
                         log_msg.package=*message;        
                         msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
                         sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
                         
                         break;
                    }
                    
                    case INVESTMENT_CONFIRMATION:{ 
                         
                        inbound_mail.id_message=IC;
                        to_queue=true;
                         
                         bzero((char *) &log_msg, sizeof(log_msg));
                         log_msg.id_message=LOG_QUEUE_EVNT_IN_INVESTMENT_C;
                         log_msg.cli_addr=cli_addr;
                         log_msg.package=*message;        
                         msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
                         sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
                         
                         break;
                    }
                    
                    case GUARD_CONFIRMATION:{ 
                         inbound_mail.id_message=GC;
                         
                         bzero((char *) &log_msg, sizeof(log_msg));
                         log_msg.id_message=LOG_QUEUE_EVNT_IN_GC;
                         log_msg.cli_addr=cli_addr;
                         log_msg.package=*message;        
                         msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
                         sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
                         
                         to_queue=true;
                         break;
                    }
                    case MISSING_CONFIRMATION:{ 
                         to_queue=true;
                         inbound_mail.id_message=MC;
                         
                         bzero((char *) &log_msg, sizeof(log_msg));
                         log_msg.id_message=LOG_QUEUE_EVNT_IN_MC;
                         log_msg.cli_addr=cli_addr;
                         log_msg.package=*message;        
                         msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
                         sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
                         
                         break;
                         
                    }
                    case ADOPTION_PAPERS:{ 
                         to_queue=true;
                         inbound_mail.id_message=AP;
                         
                         bzero((char *) &log_msg, sizeof(log_msg));
                         log_msg.id_message=LOG_QUEUE_EVNT_IN_ADOPTIONP;
                         log_msg.cli_addr=cli_addr;
                         log_msg.package=*message;        
                         msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
                         sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
                         break;
                         
                    }
                    case BOOKMARK:{ 
                         to_queue=true;
                         inbound_mail.id_message=B;
                         
                         bzero((char *) &log_msg, sizeof(log_msg));
                         log_msg.id_message=LOG_QUEUE_EVNT_IN_BOOKMARK;
                         log_msg.cli_addr=cli_addr;
                         log_msg.package=*message;        
                         msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
                         sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
                         
                         break;
                         
                    }
                    default:{
                        to_queue=false;
                        
                        bzero((char *) &log_msg, sizeof(log_msg));
                        log_msg.id_message=LOG_QUEUE_EVNT_IN_UNKNOWN;
                        log_msg.cli_addr=cli_addr;
                        log_msg.package=*message;        
                        msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
                        sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
                             
                        break;
                    }
            }
            if (to_queue){
                
                std::cout<<"el n_rg:"<< message->header.n_register <<std::endl;
                inbound_mail.package=*message;
                inbound_mail.cli_addr=cli_addr;
                msgsnd(unpacker_queue_id, (struct msgbuf *)&inbound_mail,
                sizeof(inbound_mail)-sizeof(long),IPC_NOWAIT);
                std::cout<<"pa la cola\n";
                std::cout<<"la llave:"<< unpacker_queue_id <<std::endl;
                }
            }
        
        else{
             bzero((char *) &log_msg, sizeof(log_msg));
             log_msg.id_message=LOG_QUEUE_ERR_IN_UNPACKER;
             msgsnd(log_queue_id, (struct msgbuf *)&log_msg,
             sizeof(log_msg)-sizeof(long),IPC_NOWAIT);
        }
     }
     std::cout<<"Salio\n";
     close(sockfd);
     
     return (EXIT_FAILURE);  
}